package com.dubbo.register.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ZkUtils implements Watcher
{
    public ZkUtils()
    {
        try
        {
            this.connect();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    //这里是服务器里安装的ZK，conf -> zoo.cfg 里自己配的 server
    private static final String ZK_URL = "localhost:2181";
    private static final int SESSION_TIME_OUT = 2000;

    private static ZooKeeper zookeeper = null;


    private CountDownLatch countDownLatch = new CountDownLatch(1);
    @Override
    public void process(WatchedEvent event) {
        if (event.getState() == Event.KeeperState.SyncConnected) {
            System.out.println("Watch received event");
            countDownLatch.countDown();
        }
    }

    /**连接zookeeper
     * @param
     * @throws Exception
     */
    public void connect() throws Exception{
        zookeeper = new ZooKeeper(ZK_URL, SESSION_TIME_OUT, this);
        countDownLatch.await();
        System.out.println("zookeeper connection success");
    }

    /**
     * 创建数据节点到zk中
     * 描述:在zk的根路径下创建一个节点eclipse，内容为hellozk，
     * 第三个参数是权限，我们给的是Ids.OPEN_ACL_UNSAFE 意思是 This is a completely open ACL .
     */

    public void create(String path, byte[] data)
    {

        String create = null;
        try
        {
            create = zookeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT);
        } catch (Exception e)
        {
            e.printStackTrace();
        }finally
        {
            try
            {
                zookeeper.close();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        System.out.println("创建----" + create);
    }

    /**
     * 获取节点内容
     * 描述：获取/eclipse这个节点的内容
     * 第二个参数：是否监听，这里的意思：/eclipse节点下内容发生变化时，则会通知。
     *
     * @throws Exception
     */

    public byte[] getZnode(String path)
    {
        byte[] data = new byte[0];
        try
        {
            data = zookeeper.getData("path", false, null);
            System.out.println(new String(data, "utf-8"));
        } catch (KeeperException e)
        {
            e.printStackTrace();
        } catch (Exception e)
        {
            e.printStackTrace();
        }finally
        {
            try
            {
                zookeeper.close();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 设置znode内容
     * 修改/eclipse节点的内容为helloWHB
     *
     * @throws Exception
     */
    public void setData(String path, byte[] data)
    {

        try
        {
            zookeeper.setData(path, data, -1);
            byte[] data2 = zookeeper.getData(path, false, null);
            System.out.println(new String(data2, "utf-8"));
        } catch (Exception e)
        {
            e.printStackTrace();
        }

    }

    public byte[] getData(String path)
    {
        try
        {
            return zookeeper.getData(path, false, null);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断znode是否存在
     *
     * @throws KeeperException
     * @throws InterruptedException
     */
    public boolean exist(String path)
    {

        Stat stat = null;
        try
        {
            stat = zookeeper.exists(path, false);
            System.out.println(null == stat ? "znode不存在" : "znode存在");
            if(stat != null)
            {
                return true;
            }

        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 删除znode
     * 删除/eclipse这个节点
     *
     * @throws Exception
     */
    public void delete(String path) throws Exception
    {
        // -1表示所有版本
        zookeeper.delete(path, -1);
        this.exist(path);
    }

    /**
     * 获取子节点
     *
     * @throwsException
     */
    @Test
    public List getChildren(String path)
    {
        List children = null;
        try
        {
            children = zookeeper.getChildren(path, true);
            for (Object child : children)
            {
                System.out.println(child);
            }
            Thread.sleep(Long.MAX_VALUE);//让程序一直运行，在CRT终端里 ls / watch ;create /appe www ；观察控制台打印情况
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        return children;
    }

    public void put(String path, String value)
    {
        byte[] data = value.getBytes();
        if(this.exist(path))
        {
            this.setData(path, data);
            return;
        }

        this.create(path, data);    //创建并设置数据
    }

    public String get(String path)
    {
        try
        {
            byte[] data = this.getData(path);
            return new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public void put(String path, Object obj)
    {
        //object 转byte数组，（序列化）
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray ();
            oos.close();
            bos.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        if(this.exist(path))
        {
            this.setData(path, bytes);
            return;
        }

        this.create(path, bytes);    //创建并设置数据
    }

    public Object getObj(String path)
    {
        try
        {
            byte[] data = this.getData(path);

            //byte数组转object，（反序列化）
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
            return ois.readObject();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws Exception
    {
        ZkUtils zkUtils = new ZkUtils();
//        zkUtils.connect();
        URL url = new URL("http", "localhost", 8080,"/");

        zkUtils.put("/dubbo02/com.dubbo.service.UserService", url);

        Object obj = zkUtils.getObj("/dubbo02/com.dubbo.service.UserService");
        System.out.println((URL)obj);
    }


}